package com.devbobcorn.nekoration.blocks;

import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.ActionResult;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.DoorBlock;
import net.minecraft.block.BlockState;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.Properties;
import net.minecraft.state.property.IntProperty;
import net.minecraft.loot.context.LootContext;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.block.ShapeContext;
import net.minecraft.block.enums.DoorHinge;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.util.shape.VoxelShape;

import java.util.Collections;
import java.util.List;

import com.devbobcorn.nekoration.common.VanillaCompat;

public class DyeableDoorBlock extends DoorBlock {
    protected static final VoxelShape TALL_SOUTH_SHAPE = Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 32.0D, 3.0D);
    protected static final VoxelShape TALL_NORTH_SHAPE = Block.createCuboidShape(0.0D, 0.0D, 13.0D, 16.0D, 32.0D, 16.0D);
    protected static final VoxelShape TALL_WEST_SHAPE = Block.createCuboidShape(13.0D, 0.0D, 0.0D, 16.0D, 32.0D, 16.0D);
    protected static final VoxelShape TALL_EAST_SHAPE = Block.createCuboidShape(0.0D, 0.0D, 0.0D, 3.0D, 32.0D, 16.0D);

    public static final IntProperty COLOR = Properties.LEVEL_15;
    public final boolean isTall;

    public DyeableDoorBlock(Settings settings) {
        super(settings);
        this.setDefaultState(this.stateManager.getDefaultState().with(COLOR, 14));
        isTall = false;
    }

    public DyeableDoorBlock(Settings settings, boolean tall) {
        super(settings);
        this.setDefaultState(this.stateManager.getDefaultState().with(COLOR, 14));
        isTall = tall;
    }

    protected void appendProperties(StateManager.Builder<Block, BlockState> s) {
        s.add(HALF, FACING, OPEN, HINGE, POWERED, COLOR);
    }

    @Override
    public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext ctx) {
        Direction direction = state.get(FACING);
        boolean flag = !state.get(OPEN);
        boolean flag1 = state.get(HINGE) == DoorHinge.RIGHT;
        if (isTall && state.get(HALF) == DoubleBlockHalf.UPPER)
            switch(direction) {
                case EAST:
                default:
                    return flag ? TALL_EAST_SHAPE : (flag1 ? TALL_NORTH_SHAPE : TALL_SOUTH_SHAPE);
                case SOUTH:
                    return flag ? TALL_SOUTH_SHAPE : (flag1 ? TALL_EAST_SHAPE : TALL_WEST_SHAPE);
                case WEST:
                    return flag ? TALL_WEST_SHAPE : (flag1 ? TALL_SOUTH_SHAPE : TALL_NORTH_SHAPE);
                case NORTH:
                    return flag ? TALL_NORTH_SHAPE : (flag1 ? TALL_WEST_SHAPE : TALL_EAST_SHAPE);
            }
        else 
            switch(direction) {
            case EAST:
            default:
                return flag ? EAST_SHAPE : (flag1 ? NORTH_SHAPE : SOUTH_SHAPE);
            case SOUTH:
                return flag ? SOUTH_SHAPE : (flag1 ? EAST_SHAPE : WEST_SHAPE);
            case WEST:
                return flag ? WEST_SHAPE : (flag1 ? SOUTH_SHAPE : NORTH_SHAPE);
            case NORTH:
                return flag ? NORTH_SHAPE : (flag1 ? WEST_SHAPE : EAST_SHAPE);
        }
    }

    private Block getTallerOne(Block door){
        if (door == ModBlocks.DOOR_1)
            return ModBlocks.DOOR_TALL_1;
        if (door == ModBlocks.DOOR_2)
            return ModBlocks.DOOR_TALL_2;
        if (door == ModBlocks.DOOR_3)
            return ModBlocks.DOOR_TALL_3;
        return ModBlocks.DOOR_TALL_1;
    }

    public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
        ItemStack itemStack = player.getStackInHand(hand);

        if (VanillaCompat.COLOR_ITEMS.containsKey(itemStack.getItem())) {
            world.setBlockState(pos, state.with(COLOR, VanillaCompat.COLOR_ITEMS.get(itemStack.getItem())), 3);
            return ActionResult.success(world.isClient);
        }

        if (itemStack.getItem() == Items.BONE_MEAL && !isTall){
            // Make it grow... LOL
            Direction facing = state.get(FACING);
            DoorHinge hinge = state.get(HINGE);
            boolean open = state.get(OPEN);
            boolean powered = state.get(POWERED);
            int color = state.get(COLOR);
            Block block = getTallerOne(state.getBlock());
            BlockState bs = block.getDefaultState().with(FACING, facing).with(HINGE, hinge).with(OPEN, open).with(POWERED, powered).with(COLOR, color).with(HALF, DoubleBlockHalf.LOWER);
            if (state.get(HALF) == DoubleBlockHalf.LOWER) {
                world.setBlockState(pos.up(), Blocks.AIR.getDefaultState(), 3, 0); // Prevent Droppings...
                world.setBlockState(pos, bs, 3);
                world.setBlockState(pos.up(), bs.with(HALF, DoubleBlockHalf.UPPER), 3);
            } else {
                world.setBlockState(pos, Blocks.AIR.getDefaultState(), 3, 0); // Prevent Droppings...
                world.setBlockState(pos.down(), bs, 3);
                world.setBlockState(pos, bs.with(HALF, DoubleBlockHalf.UPPER), 3);
            }
            world.addParticle(ParticleTypes.EXPLOSION_EMITTER, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 0.0D, 0.0D, 0.0D);
            return ActionResult.success(world.isClient);
        }

        return super.onUse(state, world, pos, player, hand, hit);
    }

    @Override
    public List<ItemStack> getDroppedStacks(BlockState state, LootContext.Builder builder) {
        // Drop only when the lower part's broken, or we'll get 2 dropped items...
        return state.get(HALF) == DoubleBlockHalf.LOWER ? Collections.singletonList(new ItemStack(this.asItem())) : Collections.emptyList();
    }
}